package ssiot

import (
	"fmt"
	"gitee.com/sansaniot/ssiot-gw-lib/common/global"
	msgbus2 "gitee.com/sansaniot/ssiot-gw-lib/ssiot/msgbus"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"github.com/shafreeck/cortana"
	"io"
	"os"
	"strings"
	"time"
)

var (
	MOD_NAME = "ssiot"
)

var Config struct {
	Mod struct {
		SN    string `json:"sn" yaml:"sn"`
		Model string `json:"model" yaml:"model"`
		Mqtt  struct {
			Address  string `json:"address" yaml:"address"`
			Username string `json:"username" yaml:"username"`
			Password string `json:"password" yaml:"password"`
		} `json:"mqtt" yaml:"mqtt"`
		Log struct {
			Level  string `json:"level" yaml:"level"`
			Format string `json:"format" yaml:"format"`
		} `json:"log" yaml:"log"`
	} `json:"ssiot" yaml:"ssiot"`
}

func Init() {
	args := struct {
		CfgFile string `cortana:"--config, -c, , config file"`
		SN      string `cortana:"--sn, -sn, , gateway sn"`
		Mqtt    string `cortana:"--mqtt, -m, , mqtt address:port:username:password"`
	}{}

	ignoreUnknownArgs := cortana.IgnoreUnknownArgs()
	cortana.Parse(&args, ignoreUnknownArgs)

	// 从配置文件加载配置到settings变量, 默认为./config/settings.yml，否则为命令行指定配置文件
	LoadSettingsFromYaml(args.CfgFile)

	// 从settings加载本地ssiot配置到结构体
	LoadModSettings(MOD_NAME, &Config.Mod)

	// 从命令行读取SN
	if args.SN != "" {
		Config.Mod.SN = args.SN
	}

	global.Sn = Config.Mod.SN

	// 从命令行读取mqtt配置
	if args.Mqtt != "" {
		mqttInfo := strings.Split(args.Mqtt, ":")
		Config.Mod.Mqtt.Address = fmt.Sprintf("%s:%s", mqttInfo[0], mqttInfo[1])

		if len(mqttInfo) > 2 {
			Config.Mod.Mqtt.Username = mqttInfo[2]
		}

		if len(mqttInfo) > 3 {
			Config.Mod.Mqtt.Password = mqttInfo[3]
		}
	}

	log.Logger = NewLogger(Config.Mod.Log.Format, Config.Mod.Log.Level)

	// 一定要指定sn和mqtt
	if Config.Mod.SN == "" || Config.Mod.Mqtt.Address == "" {
		panic("please set sn or mqtt in config or cli")
	}

	if !msgbus2.Connect(Config.Mod.SN, Config.Mod.Mqtt.Address, Config.Mod.Mqtt.Username, Config.Mod.Mqtt.Password) {
		log.Error().Msgf("system exit after initial connect to mqtt error")
		os.Exit(0)
	}

	if ack := login(Config.Mod.Model); ack != nil && ack.Code == 200 {
		log.Info().Msgf("login success. %s", Config.Mod.SN)
	} else {
		log.Error().Msgf("login error. %s", Config.Mod.SN)
	}

	// 从平台获取ssiot配置，并和本地配置合并保存
	SyncModSettings(MOD_NAME, &Config.Mod)

	log.Logger = NewLogger(Config.Mod.Log.Format, Config.Mod.Log.Level)
}

func Fini() {
	logout()
}

func Sn() string {
	return Config.Mod.SN
}

func NewLogger(format string, level string) zerolog.Logger {
	var writer io.Writer = os.Stdout

	if format != "json" {
		writer = zerolog.ConsoleWriter{
			Out: writer, TimeFormat: "2006-01-02 15:04:05.000",
			NoColor: writer != os.Stdout || format == "text",
		}
	}

	zerolog.TimeFieldFormat = time.RFC3339Nano

	lvl, err := zerolog.ParseLevel(level)
	if err != nil || lvl == zerolog.NoLevel {
		lvl = zerolog.InfoLevel
	}

	return zerolog.New(writer).With().Timestamp().Logger().Level(lvl)
}

func login(model string) *msgbus2.MsgIoT {
	iot := new(msgbus2.MsgIoT)
	iot.Biz = msgbus2.LOGIN
	iot.Data = &msgbus2.MsgLogin{
		Model: model,
	}

	ack := iot.SyncPublish()
	return ack
}

func logout() {
	iot := new(msgbus2.MsgIoT)
	iot.Biz = msgbus2.LOGOUT
	iot.Publish()
}
